<?php

/**
 * @author      Nguyen Duc Thuan <me@ndthuan.com>
 * @copyright   Copyright (c) 2009 Nguyen Duc Thuan <me@ndthuan.com>
 * @version     $Id: Form.php 12 2009-11-03 03:17:46Z thuan.nguyen $
 */

/**
 * This class can be used to validate form only, not to process form data
 */
class Fete_Form
{
    protected $_validators = array();
    protected $_filters = array();
    protected $_validationStates = array();
    protected $_values = array();

    /**
     *
     * @param string $field
     * @param string|array $validators
     * @return Fete_Form
     */
    public function &addValidator($field, $validators)
    {
        if (isset($this->_validators[$field])) {
            if (is_array($this->_validators[$field])) {
                if (is_array($validators)) {
                    $this->_validators[$field] = array_merge(
                        $this->_validators[$field], $validators);
                } else {
                    $this->_validators[$field][] = $validators;
                }
            } else {
                if (is_array($validators)) {
                    array_unshift($validators, $this->_validators[$field]);
                    $this->_validators[$field] = $validators;
                } else {
                    $this->_validators[$field] = array(
                        $this->_validators[$field],
                        $validators);
                }
            }
        } else {
            $this->_validators[$field] = $validators;
        }
        return $this;
    }

    /**
     *
     * @param string $field
     * @param string|array $filters
     * @return Fete_Form
     */
    public function &addFilter($field, $filters)
    {
        if (isset($this->_filters[$field])) {
            if (is_array($this->_filters[$field])) {
                if (is_array($filters)) {
                    foreach ($filters as $filter)
                    {
                        $this->_filters[$field][] = $filter;
                    }
                } else {
                    $this->_filters[$field][] = $filters;
                }
            } else {
                if (is_array($filters)) {
                    array_unshift($filters, $this->_filters[$field]);
                    $this->_filters[$field] = $filters;
                } else {
                    $this->_filters[$field] = array(
                        $this->_filters[$field],
                        $filters);
                }
            }
        } else {
            $this->_filters[$field] = $filters;
        }
        return $this;
    }

    /**
     * Filters array of data
     * @param array $data
     * @return array
     */
    public function filter($data)
    {
        foreach ($this->_filters as $field => $filterset)
        {
            if (isset($data[$field])) {
                if (is_array($filterset)) {
                    foreach ($filterset as $filter)
                    {
                        if ($filter instanceof Fete_Filter) {
                            $data[$field] = $filter->filter($data[$field]);
                        } else {
                            $data[$field] = Fete_Filter::getFilter($filter)
                                ->filter($data[$field]);
                        }
                    }
                } elseif ($filterset instanceof Fete_Filter) {
                    $data[$field] = $filterset->filter($data[$field]);
                } else {
                    $data[$field] = Fete_Filter::getFilter($filterset)
                        ->filter($data[$field]);
                }
            }
        }

        return $data;
    }

    /**
     * Validates data
     * @param array $data
     * @return boolean
     */
    public function isValid($data)
    {
        $data = $this->filter($data);
        $this->_values = $data;
        $valid = true;

        foreach ($this->_validators as $field => $ruleset)
        {
            $validationResult = array();
            if (!isset($data[$field])) {
                if ($ruleset instanceof Fete_Validator) {
                    $validationResult[$ruleset->getName()] = false;
                } elseif (is_array($ruleset)) {
                    foreach ($ruleset as $rule)
                    {
                        if ($rule instanceof Fete_Validator) {
                            $validationResult[$rule->getName()] = false;
                        } else {
                            $colonPos = strpos($rule, ':');
                            if (false !== $colonPos) {
                                $rule = substr($rule, 0, $colonPos);
                            }
                            $validationResult[$rule] = false;
                        }
                    }
                } else {
                    $colonPos = strpos($ruleset, ':');
                    if (false !== $colonPos) {
                        $ruleset = substr($ruleset, 0, $colonPos);
                    }
                    $validationResult[$ruleset] = false;
                }
                $valid = false;
            } else {
                if($ruleset instanceof Fete_Validator) {
                    $check = $ruleset->isValid($data[$field]);
                    $validationResult[$ruleset->getName()] = $check;

                    if (false === $check) {
                        $valid = false;
                    }
                } elseif (is_array($ruleset)) {
                    foreach ($ruleset as $rule)
                    {
                        if ($rule instanceof Fete_Validator) {
                            $check = $rule->isValid($data[$field]);
                            $validationResult[$rule->getName()] = $check;
                        } else {
                            $check = call_user_func(array(
                                Fete_Validator::getValidator($rule),
                                'isValid'
                                ), $data[$field]);
                            $colonPos = strpos($rule, ':');
                            if (false !== $colonPos) {
                                $rule = substr($rule, 0, $colonPos);
                            }
                            $validationResult[$rule] = $check;
                        }

                        if (false === $check) {
                            $valid = false;
                        }
                    }
                } else {
                    $check = call_user_func(array(
                        Fete_Validator::getValidator($ruleset),
                        'isValid'
                        ), $data[$field]);
                    $colonPos = strpos($ruleset, ':');
                    if (false !== $colonPos) {
                        $ruleset = substr($ruleset, 0, $colonPos);
                    }
                    $validationResult[$ruleset] = $check;

                    if (false === $check) {
                        $valid = false;
                    }
                }
            }
            $this->_validationStates[$field] = $validationResult;
        }

        return $valid;
    }

    /**
     *
     * @return array
     */
    public function getValues()
    {
        return $this->_values;
    }

    /**
     *
     * @param string $key
     * @return string
     */
    public function getValue($key)
    {
        if (isset($this->_values[$key])) {
            return $this->_values[$key];
        }
        return null;
    }

    /**
     * Gets validatios states of a field
     * @param string $field
     * @return array
     */
    public function getValidationStates($field)
    {
        return isset($this->_validationStates[$field])
            ? $this->_validationStates[$field] : array();
    }

    /**
     *
     * @return array
     */
    public function getAllValidationStates()
    {
        return $this->_validationStates;
    }

    public function init() {}

    public function  __construct()
    {
        $this->init();
    }
}